"""
!/usr/bin/env python
-*- coding: utf-8 -*-
@Author  : MarkJia
@Site    : 
@File    : 33. 单例模式 和 工厂模式.py
"""


# 单例模式：使不同对象的物理地址相同，提升系统性能
class Book:
    # __new__ 是在实例创建之前调用的，因为它的任务就是创建实例然后返回该实例（返回给__init__），是个静态方法
    def __new__(cls, title):
        if not hasattr(cls, '_ins'):
            cls._ins = super().__new__(cls)
        print('执行：__new__ 静态方法')
        return cls._ins

    # __init__ 是当实例对象创建后被调用的，然后设置对象属性的初始值
    def __init__(self, title):
        print('执行：__init__ 实列方法')
        super().__init__()
        self.title = title


if __name__ == '__main__':
    b = Book('The Spider Book')
    b2 = Book('The Spider Book')
    # 不同对象 同一个内存地址
    print(id(b))  # 2713860242256
    print(id(b2))  # 2713860242256
    print(b.title)
    print(b2.title)

"""
单例模式下 ： 不管调用多少次，始终只进行一次初始化。产生一个实例对象
单例模式的作用是确保一个类只有一个实例对象，并且提供一个访问该实例的全局访问点（如配置文件的读取，只需要在系统启动时读取一次即可，生成一个实例对象，反复调用时也只有
这一个实例对象，降低了系统的开销）
"""


class MySingletom:
    _obj = None  # 类属性的值是 None
    _init_flag = True  # 设置该属性的目的是测试是否进行过第一次的初始化

    def __new__(cls, *args, **kwargs):  # 重写new方法
        if cls._obj == None:  # 说明该类尚未进行第一次创建实例对象
            cls._obj = object.__new__(cls)  # 调用父类 object 的创建方式，将对象 cls 传入，创建一个单例的对象
        return cls._obj

    def __int__(self, name):
        if MySingletom._init_flag == True:  # 若未进行过第一个类的初始化，则进行初始化。并置标位为 False
            print('init....')
            self.name = name
            MySingletom._init_flag = False

if __name__ == '__main__':
    a = MySingletom('aaa')
    b = MySingletom('bbb')
    print(a)
    print(b)


# 工厂模式
# 实现了创建者和调用者的分离，使用专门的工厂类将选择实现类，创建对象进行统一的管理和控制

class CarFactor:  # 创建工厂类
    def create_car(self, brand):  # 将创建车的功能统一集中到一个方法中
        if brand == '奔驰':
            return Benz()  # 若传入的参数是'奔驰',则创建一个 Benz 类的对象
        elif brand == '宝马':
            return BMW()
        elif brand == '比亚迪':
            return BYD()
        else:
            return '无法创建'


class Benz:
    pass


class BMW:
    pass


class BYD:
    pass


# 创建一个工厂类的对象
factory = CarFactor()
c1 = factory.create_car('宝马')  # 使用刚创建的对象，直接调用 create_car 方法来创建各种不同型号的对象
